using EasyNetQ;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace MF.Bus
{
    /**
     * @Description: 消息总线扩展
     * @Auther: 毕苗苗
     */
    public static class MFBusExtention
    {
        static IBus bus;
        /// <summary>
        /// 向容器中添加消息总线
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddMFBus(this IServiceCollection services, IConfiguration configuration)
        {
            var mqConnection = configuration.GetSection("BusMQConnection").Value;
            if(string.IsNullOrEmpty(mqConnection))
            {
                throw new Exception("BusMQConnection消息总线MQ连接地址没有配置!");
            }
            //var connection = "host=139.159.240.197:5672;virtualHost=bmm_test;username=admin;password=sydj520.com";

            bus = RabbitHutch.CreateBus(mqConnection);

            services.AddSingleton<IBus>(bus);

            //注入MFBus发布
            services.AddSingleton<IMFBus,MFBusDefault>();
            //注入统一消费入口
            services.AddSingleton<MFConsumeEntry>();

            AddSubscribes(services, configuration);

        }

        ///// <summary>
        ///// 添加总线订阅
        ///// </summary>
        ///// <param name="services"></param>
        ///// <param name="configuration"></param>
        //private static void AddSubscribes(IServiceCollection services, IConfiguration configuration)
        //{
        //    //var provider = services.BuildServiceProvider();
        //    ////var provider = scope.ServiceProvider;

        //    //var entry = provider.GetService<MFConsumeEntry>();

        //    //bus.PubSub.SubscribeAsync<BusMessage>("", entry.ComsumeEntry, x => x.WithTopic(topic));

        //    ////获取或者创建订阅主体的对象(最好注入容器中,不要把实例化交给此方法)
        //    ////将topic(routing-key)和队列一起绑定到消费方法
        //    //var targetObj = (MFConsumeEntry)ActivatorUtilities.GetServiceOrCreateInstance(provider,typeof(MFConsumeEntry));
        //    ////获取订阅主题的消费方法
            
        //    //var actionObj = (Action<BusMessage>)Action<BusMessage>.CreateDelegate(typeof(Action<BusMessage>), targetObj, targetObj.ComsumeEntry().GetType());



        //    //程序集返回
        //    var list = DependencyContext.Default.RuntimeLibraries
        //      .Where(o => !o.Serviceable && o.Type != "package"
        //      //&& ListAssemblyStartsName.Exists(a => o.Name.StartsWith(a))
        //      )
        //      .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
        //    //取出包含有Controller和Domain的程序集
        //    var assemblies = list.Where(a => a.ExportedTypes.Where(b => TypeJudge.IsController(b.GetTypeInfo()) || TypeJudge.IsDomain(b.GetTypeInfo())).Count() > 0);

        //    //只处理Controller和Domain层的类
        //    foreach (var assembly in assemblies)
        //    {
        //        var types = assembly.ExportedTypes;
        //        var typesInfo = types.Where(a => TypeJudge.IsController(a.GetTypeInfo()) || TypeJudge.IsDomain(a.GetTypeInfo()));
        //        if (typesInfo == null || typesInfo.Count() == 0) return;
        //        foreach (var type in typesInfo)
        //        {
        //            var typeInfo = type.GetTypeInfo();
        //            //只订阅有Subscribe特性,并且特性topic值不为空的方法
        //            var methods = typeInfo.GetRuntimeMethods().Where(a => a.GetCustomAttributes<SubscribeAttribute>(true) != null
        //            && !string.IsNullOrEmpty(a.GetCustomAttributes<SubscribeAttribute>(true).FirstOrDefault()?.Topic));
        //            if (methods == null || methods.Count() == 0) continue;
        //            foreach (var method in methods)
        //            {

        //                var topicMethodAttributes = method.GetCustomAttributes<SubscribeAttribute>(true);
        //                using var scope = services.BuildServiceProvider().CreateScope();
        //                var provider = scope.ServiceProvider;
        //                //获取或者创建订阅主体的对象(最好注入容器中,不要把实例化交给此方法)
        //                var targetObj = ActivatorUtilities.GetServiceOrCreateInstance(provider, typeInfo.AsType());
        //                //获取订阅主题的消费方法
        //                var actionObj = (Action<BusMessage>)Action<BusMessage>.CreateDelegate(typeof(Action<BusMessage>), targetObj, method);
        //                var queueName = topicMethodAttributes.FirstOrDefault().Queue;
        //                var topic = topicMethodAttributes.FirstOrDefault().Topic;

        //                //如果队列名为空,则用方法名作为队列名
        //                if (string.IsNullOrEmpty(queueName))
        //                {
        //                    queueName = method.Name;
        //                }

        //                //将topic(routing-key)和队列一起绑定到消费入口中
        //                var entry = provider.GetService<MFConsumeEntry>();

        //                bus.PubSub.SubscribeAsync<BusMessage>(queueName, entry.ComsumeEntry, x => x.WithTopic(topic));
        //            }
        //        }
        //    }

        //}

        /// <summary>
        /// 添加总线订阅
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        private static void AddSubscribes(IServiceCollection services, IConfiguration configuration)
        {
            //程序集返回
            var list = DependencyContext.Default.RuntimeLibraries
              .Where(o => !o.Serviceable && o.Type != "package"
              //&& ListAssemblyStartsName.Exists(a => o.Name.StartsWith(a))
              )
              .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
            //取出包含有Controller和Domain的程序集
            var assemblies = list.Where(a => a.ExportedTypes.Where(b => TypeJudge.IsController(b.GetTypeInfo()) || TypeJudge.IsDomain(b.GetTypeInfo())).Count() > 0);

            //只处理Controller和Domain层的类
            foreach (var assembly in assemblies)
            {
                var types = assembly.ExportedTypes;
                var typesInfo = types.Where(a => TypeJudge.IsController(a.GetTypeInfo()) || TypeJudge.IsDomain(a.GetTypeInfo()));
                if (typesInfo == null || typesInfo.Count() == 0) return;
                foreach (var type in typesInfo)
                {
                    var typeInfo = type.GetTypeInfo();
                    //只订阅有Subscribe特性,并且特性topic值不为空的方法
                    var methods = typeInfo.GetRuntimeMethods().Where(a => a.GetCustomAttributes<SubscribeAttribute>(true) != null
                    && !string.IsNullOrEmpty(a.GetCustomAttributes<SubscribeAttribute>(true).FirstOrDefault()?.Topic));
                    if (methods == null || methods.Count() == 0) continue;
                    foreach (var method in methods)
                    {

                        var topicMethodAttributes = method.GetCustomAttributes<SubscribeAttribute>(true);
                        using var scope = services.BuildServiceProvider().CreateScope();
                        var provider = scope.ServiceProvider;
                        //获取或者创建订阅主体的对象(最好注入容器中,不要把实例化交给此方法)
                        var targetObj = ActivatorUtilities.GetServiceOrCreateInstance(provider, typeInfo.AsType());
                        //获取订阅主题的消费方法
                        var actionObj = (Action<BusMessage>)Action<BusMessage>.CreateDelegate(typeof(Action<BusMessage>), targetObj, method);
                        var queueName = topicMethodAttributes.FirstOrDefault().Queue;
                        var topic = topicMethodAttributes.FirstOrDefault().Topic;
                        //如果队列名为空,则用方法名作为队列名
                        if (string.IsNullOrEmpty(queueName))
                        {
                            queueName = method.Name;
                        }
                        //将topic(routing-key)和队列一起绑定到消费方法
                        bus.PubSub.SubscribeAsync<BusMessage>(queueName, actionObj, x => x.WithTopic(topic));
                    }
                }
            }

        }


    }
}
